#ifndef STATSxx_MACHINE_LEARNING_NEURALNET_NEURON_HPP
#define STATSxx_MACHINE_LEARNING_NEURALNET_NEURON_HPP


// STL
#include <fstream>
#include <vector>

// Boost
#include <boost/serialization/serialization.hpp> // boost::serialization::
#include <boost/serialization/vector.hpp>        // serialize std::vector<>


//=========================================================
// NEURON
//=========================================================
class NEURON
{

public:

    enum TYPE
    {
        INPUT,
        HIDDEN,
        BIAS,
        OUTPUT
    };
    TYPE type;

    enum ACTIVATION_FUNC
    {
        IDENTITY,
        LOGISTIC,
        TANH,
        SOFTPLUS,
        SOFTMAX
    };
    ACTIVATION_FUNC act_func;

    int m_ID;

    std::vector<double> m_output;   // OUTPUT FOLLOWING ACTIVATION, POSSIBLY MEMORY (RECCURRENT NEURON)
    std::vector<double> m_errors;   // ERROR AT NEURON (TYPICALLY USED IN BACK-PROPAGATION OF ERROR)


    NEURON();
    NEURON(int ID, NEURON::TYPE tp, NEURON::ACTIVATION_FUNC af);
    ~NEURON();

    void   clear_memory();
    void   clear_errors();
    void   deactivate();

    void   activate();
    void   activate_error();

    bool   is_activated();
    double get_output(unsigned int tdelay);
    double get_error(unsigned int tdelay);

    void   override_activation(bool flag);
    void   override_output(unsigned int tdelay, double val);

private:

    bool m_isActivated;             // NEURON HAS BEEN ACTIVATED (USED FOR ERROR PROPAGATION TOO)

    // (Boost) SERIALIZATION
    friend class boost::serialization::access;

    template<class Archive>
    void serialize(
                   Archive            &ar,
                   const unsigned int  version
                   )
    {
        ar & this->type;

        ar & this->act_func;

        ar & this->m_ID;

        ar & this->m_output;
        ar & this->m_errors;

        ar & this->m_isActivated;
    }

};

// FOR SORTING BY m_ID ...
struct NEURON_ID_less_than
{
    inline bool operator() (const NEURON& n1, const NEURON& n2)
    {
        return (n1.m_ID < n2.m_ID);
    }
};

#include "statsxx/machine_learning/NeuralNet/Neuron/Neuron.cpp"


#endif
